home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Libraries / grayimage / sys_open.cc < prev    next >
Encoding:
Text File  |  1994-06-30  |  4.9 KB  |  125 lines  |  [TEXT/R*ch]

  1. // This may look like C code, but it is really -*- C++ -*-
  2. /*
  3.  ************************************************************************
  4.  *
  5.  *           The lowest but one level file opener
  6.  *
  7.  * The program is intended to serve as an interface between the system
  8.  * call for opening the file and the filebuf layer of the I/O G++ streams.
  9.  * The function sys_open pretends to be <sys/file.h>'s open()
  10.  *    int open(const char * filename, const int mode, const int mask)
  11.  *
  12.  * and extends functionality of the latter by the following
  13.  * - if the file cannot be opened, the program writes a diagnostic
  14.  *   message (through report_error()), indicating the problem and
  15.  *   the name of the file of question.
  16.  *
  17.  * - the name of the file to open may be specified now as "| command"
  18.  *   or "command |" i.e. as a pipe. The command is launched in a
  19.  *   subprocess through '/bin/sh' with its standard input/output
  20.  *   hooked to the file through pipe().
  21.  *
  22.  * Installation
  23.  * modify filebuf.C file in the libg++ as follows
  24.  * add the declaration at the beginning of the file
  25.  *  extern int sys_open(const char * filename, const int mode, const int mask);
  26.  * and then replace all occurences of " ::open(" for " ::sys_open("
  27.  *
  28.  * Implementation of _popen is due to
  29.  *     Copyright (C) 1991, 1992 Per Bothner. (bothner@cygnus.com)
  30.  *
  31.  ************************************************************************
  32.  */ 
  33.  
  34. #include <std.h>
  35. #include <sys/file.h>
  36. #include <errno.h>
  37.  
  38. #define report_error _error
  39. #include "myenv.h"            // Declares "error.h"
  40.  
  41. /*
  42.  *------------------------------------------------------------------------
  43.  * 
  44.  * Launch the 'command' through 'sh' and hook its standard input/output
  45.  *                to a file.
  46.  * The file handler is returned, or -1 in case of error
  47.  *
  48.  * Important !
  49.  * First argument, 'command' should point to a string buffer that lives
  50.  * long enough (it'd better be static). This is because the command
  51.  * pointer is to be passed to the subprocess that definitely won't
  52.  * complete before the function _popen() exits. So the care should
  53.  * be taken to make sure that 'command' still points to a valid,
  54.  * undisposed buffer even after the function exits. The static
  55.  * buffer will do it.
  56.  * The second argument, mode is assumed to take only two values,
  57.  * either O_RDONLY or O_WRONLY.
  58.  */
  59.  
  60. static int _popen(const char * command, int mode)
  61. {
  62.   struct { int read_fd, write_fd; } pipe_fds;
  63.  
  64.   int parent_end, child_end;        // ends of the pipe
  65.   int child_std_end;            // File handlrs for stdin/out
  66.  
  67.   if( ::pipe((int *)&pipe_fds) < 0 )    // Creating a pipe
  68.     return -1;
  69.  
  70.   if( mode == O_RDONLY )        // We're reading, command is writing
  71.     parent_end = pipe_fds.read_fd, child_end  = pipe_fds.write_fd,
  72.     child_std_end = 1;            // stdout for command
  73.   else                    // Command is reading, we're writing
  74.     parent_end = pipe_fds.write_fd, child_end  = pipe_fds.read_fd,
  75.     child_std_end = 0;            // stdin for command
  76.  
  77.     int kid_id = ::fork();
  78.     if( kid_id == 0 )
  79.     {                    // We're in kid's process
  80.       ::close(parent_end);        // which is to execute the command
  81.       if( child_end != child_std_end )
  82.       {
  83.     ::dup2(child_end, child_std_end);
  84.     ::close(child_end);
  85.       }
  86.       ::execl("/bin/sh", "sh", "-c", command, 0);
  87.       ::_exit(127);            // Executed only if execl failed!
  88.     }
  89.  
  90.     ::close(child_end);            // We're in the parent process
  91.     if( kid_id < 0 )
  92.       ::close(parent_end), parent_end = -1;    // if fork failed
  93.  
  94.   return parent_end;
  95. }
  96.  
  97. /*
  98.  *------------------------------------------------------------------------
  99.  *              Phony 'open'
  100.  */
  101.  
  102. int sys_open(const char *filename, const int mode, const int mask)
  103. {
  104.   int fd = -1;            // File handler of the file being opened
  105.  
  106.   register char *p = strchr(filename,'|');
  107.   if( p == 0 )
  108.     fd = ::open(filename,mode,mask);    // Regular open(), without pipes
  109.  
  110.   else if( p == strspn(filename," ") + filename )
  111.   {                    // if '|' is the 1st non-blank of fname
  112.                     // create the pipe to write to
  113.     if( (mode & (O_WRONLY | O_RDONLY)) != O_WRONLY )
  114.       report_error
  115.     ("File name '%s' looks like the pipe to write to,"
  116.      "\nbut the open mode is not WRITE_ONLY",filename);
  117.     fd = _popen(p+1,O_WRONLY);        // p+1 points to the char right after |
  118.   }
  119.   else if( *(p+1) == '\0' )        // '|' is the last char of the filename
  120.   {                    // Create the pipe to read from
  121.     static char tempname[200];        // tempname MUST be static
  122.     if( p-filename >= (signed)sizeof(tempname) )
  123.       report_error ("Pipe name is way too long!" ); // Copy the file name up to
  124.     strncpy(tempname,filename,p-filename);        // (but not including) '|'
  125.     if( (mode & (O_WRONLY | O_RDONLY))